package com.ewancle.studiousfamilybackend.config;

import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import com.ewancle.studiousfamilybackend.handler.SocketIOHandler;
import com.ewancle.studiousfamilybackend.handler.TestHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Optional;

// 参考：https://blog.csdn.net/qq407995680/article/details/131956249 和 https://juejin.cn/post/7308519016976695331
// 官网：https://socket.io/zh-CN/docs/v4/
// vue3 :https://blog.csdn.net/weixin_50637077/article/details/132897514 和 https://blog.csdn.net/mxs1226/article/details/133852460
// redis: https://blog.51cto.com/u_16175442/6742218 和 https://blog.csdn.net/qq_35842042/article/details/130790840
//  https://blog.csdn.net/qq_38893133/article/details/131891993
@Configuration
public class SocketIOConfig {

    @Component
    @Slf4j
    static class SocketIOServerRunner implements CommandLineRunner, DisposableBean {

        private final SocketIOServer socketIOServer;

        private final TestHandler testHandler;

        private final SocketIOHandler socketIOHandler;

        public SocketIOServerRunner(SocketIOServer socketIOServer, TestHandler testHandler, SocketIOHandler socketIOHandler){

            this.socketIOServer = socketIOServer;
            this.testHandler = testHandler;
            this.socketIOHandler = socketIOHandler;
        }

        @Override
        public void run(String... args) throws Exception {
            //namespace分别交给各自的Handler监听,这样就可以隔离，只有客户端指定namespace，才能访问对应Handler。
            //比如：http://localhost:9999/test?userId=12345
            socketIOServer.getNamespace("/test").addListeners(testHandler);
            socketIOServer.getNamespace("/socketIO").addListeners(socketIOHandler);
            socketIOServer.start();
            log.info("SocketIOServer==============================启动成功");

        }


        @Override
        public void destroy() throws Exception {
            //如果用kill -9  这个监听是没用的，有可能会导致你服务kill掉了，但是socket服务没有kill掉
            socketIOServer.stop();
            log.info("SocketIOServer==============================关闭成功");
        }
    }


    @Value("${socketio.host}")
    private String host;

    @Value("${socketio.port}")
    private Integer port;

    @Value("${socketio.bossCount}")
    private int bossCount;

    @Value("${socketio.workCount}")
    private int workCount;

    @Value("${socketio.allowCustomRequests}")
    private boolean allowCustomRequests;

    @Value("${socketio.upgradeTimeout}")
    private int upgradeTimeout;

    @Value("${socketio.pingTimeout}")
    private int pingTimeout;

    @Value("${socketio.pingInterval}")
    private int pingInterval;

    @Value("${socketio.namespaces}")
    private String[] namespaces;

    @Bean
    public SocketIOServer socketIOServer() {
        SocketConfig socketConfig = new SocketConfig();
        socketConfig.setTcpNoDelay(true);
        socketConfig.setSoLinger(0);
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        config.setSocketConfig(socketConfig);
        config.setHostname(host);
        config.setPort(port);
        config.setBossThreads(bossCount);
        config.setWorkerThreads(workCount);
        config.setAllowCustomRequests(allowCustomRequests);
        config.setUpgradeTimeout(upgradeTimeout);
        config.setPingTimeout(pingTimeout);
        config.setPingInterval(pingInterval);

        //服务端
        final SocketIOServer server = new SocketIOServer(config);

        //添加命名空间（如果你不需要命名空间，下面的代码可以去掉）
        Optional.ofNullable(namespaces).ifPresent(nss ->
                Arrays.stream(nss).forEach(server::addNamespace));

        return server;
    }

    //这个对象是用来扫描socketio的注解，比如 @OnConnect、@OnEvent
    @Bean
    public SpringAnnotationScanner springAnnotationScanner() {
        return new SpringAnnotationScanner(socketIOServer());
    }

}
